#pragma once
#include <iostream>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

#define defigDefualtCap 10

template <class T> 
class BlockQueue
{
private:
   // 阻塞队列是否已满
   bool isfull()
   {
      return !(_que.size() < _capacity);
   }
   
   // 阻塞队列是否为空
   bool isempty()
   {
      return _que.size() == 0;
   }

public:
   BlockQueue(int capacity = defigDefualtCap)
      :_capacity(capacity)
   {
     pthread_mutex_init(&_mtx,nullptr);
     pthread_cond_init(&_empty,nullptr);
     pthread_cond_init(&_full, nullptr);
   }

   ~BlockQueue()
   {
    pthread_mutex_destroy(&_mtx);
    pthread_cond_destroy(&_empty);
    pthread_cond_destroy(&_full);
   }  

   int push(const T& in)
   {
      //pthread_mutex_lock(&_mtx);
      LockGuard kgd(&_mtx);
      {
      kgd.lockguard();
      if (isfull())  // 检测阻塞队列是否未满，满了就先阻塞到，条件变量为队列满的队列中
         pthread_cond_wait(&_full, &_mtx);
      // 这里锁的意义：队列满，push操作陷入阻塞，同时自动释放锁；等到下次，被唤醒时，自动申请到锁，继续push
      _que.push(in);  // 输入后唤醒客户读取数据
      if (_que.size() >= (_capacity / 2))
      pthread_cond_signal(&_empty);
      }// pthread_mutex_unlock(&_mtx);
      return 0;
   }
   
   int pop(T& a)
   {
      LockGuard kgd(&_mtx);
      {
      kgd.lockguard();
      //pthread_mutex_lock(&_mtx);
      if (isempty())
      {
         pthread_cond_signal(&_full); 
         pthread_cond_wait(&_empty, &_mtx);
      }
      a = _que.front();
      _que.pop();
      }//pthread_mutex_unlock(&_mtx);
      // pthread_cond_signal(&_full); 
      return 0;
   }
   
private:
    std::queue<T> _que;   // 阻塞队列
    int _capacity;   // 队列值咯
    pthread_mutex_t _mtx;
    pthread_cond_t  _empty; // 为什么要使用2个条件变量，这不代表要2个
    pthread_cond_t _full;
};






